package com.rui.study.commons.study.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDKDynamicProxy implements DynamicProxy, InvocationHandler {

    private TargetSource targetSource;

    private ClassLoader classLoader;

    private Advisor advisor;


    /**************************************************
     *                  CONSTRUCTOR                   *
     **************************************************/

    public JDKDynamicProxy(TargetSource targetSource, Advisor advisor) {
        this.targetSource = targetSource;
        this.advisor = advisor;
    }


    /**************************************************
     *                 PUBLIC METHOD                  *
     **************************************************/

    @Override
    public Object getProxy() {
        Class<?>[] interfaces = targetSource.getInterfaces();
        ClassLoader classLoader = getClassLoader();
        return Proxy.newProxyInstance(classLoader, interfaces, this);
    }

    @Override
    public Object invoke(Object o, Method method, Object[] arges) throws Throwable {
        advisor.before();
        Object retVal = null;
        try {
            retVal = method.invoke(targetSource.getTargetObjec(), arges);
            advisor.after();
        } catch (Exception e) {
            advisor.onException();
        } finally {
            advisor.onFinal();
        }
        return retVal;
    }


    /**************************************************
     *                 GETTER/SETTER                  *
     **************************************************/

    public TargetSource getTargetSource() {
        return targetSource;
    }

    public void setTargetSource(TargetSource targetSource) {
        this.targetSource = targetSource;
    }

    public ClassLoader getClassLoader() {
        if (this.classLoader == null)
            this.classLoader = getTargetSource().getTargetObjec().getClass().getClassLoader();
        if (this.classLoader == null)
            this.classLoader = this.getClassLoader();
        return this.classLoader;
    }

    public void setClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public Advisor getAdvisor() {
        return advisor;
    }

    public void setAdvisor(Advisor advisor) {
        this.advisor = advisor;
    }
}
